/**
 * @file    iap_master.c
 * @brief   JBD主机升级协议
 * @author  Liuwei
 * @version 1.0.1
 * @date    2023-05-24
 * 
 * @copyright Copyright (c) 2023 JBD-Energy Storage Technology Co. LTD
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version   <th>Author   <th>Description
 * <tr><td>2023-05-24 <td>1.0.1     <td>name     <td>首次创建
 * </table>
 */

/* includes ------------------------------------------------------------------*/
#include "iap_master.h"
#include "drv_flash.h"
#include "cfg_prj.h"
#include "If_com.h"
#include "iap_boot.h"
#include "crc.h"
#include "modbus_app.h"
#include "iap_boot.h"
#include "boot_param.h"
/* macro/define --------------------------------------------------------------*/
#define TIMEOUT_TRY_TIMES             (10)
#define ONE_PACK_SIZE                 (512)
/* typedef -------------------------------------------------------------------*/
enum
{
    UP_STEP_IDLE  = 0x00 ,
    UP_STEP_START , 
    UP_STEP_RESET , 
    UP_STEP_UPGRADE , 
    UP_STEP_UP_CMP ,
};
/* local functions -----------------------------------------------------------*/
static void iap_master_send_upgrade_cmd(uint16_t salve_addr ,uint8_t com_id);
static void iap_master_send_data_frame(uint16_t salve_addr ,uint16_t pack_sn , uint8_t com_id);
static void iap_master_send_pack_num(uint16_t salve_addr ,uint16_t max_num ,uint8_t com_id);
static uint8_t iap_master_is_status_ok(uint16_t now_pack_sn,uint8_t *rx_buf, uint16_t rx_num);
/* static variables ----------------------------------------------------------*/
//static uint8_t status_cmd[] = {0xBB,0x3A,0x03,0x00,0x00,0x00,0x41,0xFC,0xCC};
//#define STATUS_CMD_SIZE        (sizeof(status_cmd)/sizeof(status_cmd[0]))
iap_master_data_type iap_master_data = {0};
static uint8_t upgrade_step = 0;
uint16_t step_time_cnt = 0;
uint16_t send_times = 0;
static uint8_t cmd_try_times = 0;
static uint16_t up_slave_pack_sn = 0;
static uint8_t master_tx_buf[1030] = {0};
static uint8_t master_rx_buf[200] = {0};
static uint16_t master_rx_num = 0;
/* global variables ----------------------------------------------------------*/

/** ------------------------------------------------------------------------- *
  *                             Global function
 ** ------------------------------------------------------------------------- */
/**
 * @brief  主机升级任务
 * @param  rx_buf
 * @param  rx_len
 * @return uint8_t 
 */
uint8_t iap_master_run_upgrade_slave(uint16_t cycle , uint8_t com_id)
{
    switch(upgrade_step)
    {
        case UP_STEP_START:
            step_time_cnt += cycle;
            iap_master_data.salve_addr = 0x02;
            up_slave_pack_sn = 0;
            upgrade_step = UP_STEP_RESET;
			iap_master_send_upgrade_cmd(iap_master_data.salve_addr , com_id);
            break;
        case UP_STEP_RESET:
            step_time_cnt += cycle;
            if(step_time_cnt >= 1000)
            {
                ++ cmd_try_times;
                if(cmd_try_times < 3)
                {
                    iap_master_send_upgrade_cmd(iap_master_data.salve_addr , com_id);
                }
				else if(cmd_try_times <= 5)
				{
					iap_master_send_pack_num(iap_master_data.salve_addr ,0x1000, com_id);
				}
				else
				{
					cmd_try_times = 0;
                    upgrade_step = UP_STEP_UP_CMP;
				}
                step_time_cnt = 0;
            }

            if(TRUE == If_com_recv_comp(com_id))
		    {
			    master_rx_num = If_com_get_recv_num(com_id);
                If_com_get_recv_buf(com_id , master_rx_buf , master_rx_num);
                if(TRUE == iap_master_is_status_ok(0 ,master_rx_buf , master_rx_num))
                {
                    upgrade_step = UP_STEP_UPGRADE;
					iap_master_send_data_frame(iap_master_data.salve_addr , up_slave_pack_sn, com_id);
                }
                If_com_start_recv(com_id);

                step_time_cnt = 0;
            }
            break;
        case UP_STEP_UPGRADE:
			step_time_cnt += cycle; 
            if(step_time_cnt >= 1000)
            {
                cmd_try_times ++ ;
                if(cmd_try_times >= 10)
                {
                    upgrade_step = UP_STEP_UP_CMP;
                }
				else
				{
                	iap_master_send_data_frame(iap_master_data.salve_addr , up_slave_pack_sn, com_id);
				}
				step_time_cnt = 0;
            }

            if(TRUE == If_com_recv_comp(com_id))
		    {
			    master_rx_num = If_com_get_recv_num(com_id);
                If_com_get_recv_buf(com_id , master_rx_buf , master_rx_num);
                if(TRUE == iap_master_is_status_ok(up_slave_pack_sn,master_rx_buf , master_rx_num))
                {
                    ++ up_slave_pack_sn;
					if(up_slave_pack_sn * ONE_PACK_SIZE < boot_param_read_par(BP_ID_APP_SIZE))
					{
						iap_master_send_data_frame(iap_master_data.salve_addr , up_slave_pack_sn, com_id);
					}
					else
					{
						upgrade_step = UP_STEP_UP_CMP;
					}
                    
                    cmd_try_times = 0;
                    step_time_cnt = 0;
                }
                else
                {
                    iap_master_send_data_frame(iap_master_data.salve_addr , up_slave_pack_sn, com_id);
                    step_time_cnt = 0;
                }
                If_com_start_recv(com_id);

                step_time_cnt = 0;
            }
            break;
        case UP_STEP_UP_CMP:
            iap_master_data.salve_addr ++ ;
            if(iap_master_data.salve_addr >= CFG_PARALLEL_NUM)
            {
                iap_master_data.salve_addr = 2;
                iap_master_data.upgrade_state = 0;
                upgrade_step = UP_STEP_START;
                up_slave_pack_sn = 0;
            }
            else
            {
                cmd_try_times = 0;
                step_time_cnt = 0;
                upgrade_step = UP_STEP_RESET;
            }
            break;
        default:
            upgrade_step = UP_STEP_START;
            iap_master_data.upgrade_state = UPGRADE_CMD_RUN;
            break;
    }
	
	if(UPGRADE_CMD_RUN == iap_master_data.upgrade_state)
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

void iap_master_start_upgrade_slave(void)
{
    iap_master_data.upgrade_state = UPGRADE_CMD_RUN;
    iap_master_data.salve_addr = 2;
    upgrade_step = UP_STEP_START;
    cmd_try_times = 0;
    up_slave_pack_sn = 0;
}

uint8_t iap_master_is_upgrade_slave(void)
{
	if(UPGRADE_CMD_RUN == iap_master_data.upgrade_state)
		return TRUE;
	else
		return FALSE;
}

static void iap_master_send_pack_num(uint16_t salve_addr ,uint16_t max_num ,uint8_t com_id)
{
	uint8_t tx_buf[10] = {0};
    tx_buf[0] = 0xBB;
    tx_buf[1] = 0x3A;
    tx_buf[2] = 0x01;
    tx_buf[3] = 0x00;
    tx_buf[4] = 0x5D;
    tx_buf[5] = 0x50;
    tx_buf[6] = 0xCC;

    If_com_send_str(com_id ,tx_buf , 7);
}

static void iap_master_send_upgrade_cmd(uint16_t salve_addr ,uint8_t com_id)
{
    uint16_t crc_code = 0;
	uint8_t tx_buf[20] = {0};
    tx_buf[0] = 0xDD;
    tx_buf[1] = salve_addr;
    tx_buf[2] = 0x5A;
    tx_buf[3] = 0x02;
    tx_buf[4] = 0x02;
    tx_buf[5] = 0x12;
    tx_buf[6] = 0x34;
    
    crc_code = calc_sum_crc(&tx_buf[1] , 6);
    tx_buf[7] = crc_code >> 8;
    tx_buf[8] = crc_code & 0xff;
    tx_buf[9] = 0x77;

    If_com_send_str(com_id ,tx_buf , 10);
}

static void iap_master_send_data_frame(uint16_t salve_addr ,uint16_t pack_sn , uint8_t com_id)
{
    uint16_t crc_code = 0;
	uint16_t idx_cnt = 0;
    master_tx_buf[idx_cnt ++ ] = 0xBB;
    master_tx_buf[idx_cnt ++ ] = 0x30;
    master_tx_buf[idx_cnt ++ ] = ONE_PACK_SIZE / 32;
    master_tx_buf[idx_cnt ++ ] = pack_sn >> 8;
    master_tx_buf[idx_cnt ++ ] = pack_sn & 0xff;
	
	drv_flash_init();
	
    drv_flash_read_data(pack_sn * ONE_PACK_SIZE + APP_START_ADDR , &master_tx_buf[5] , ONE_PACK_SIZE);
	
	drv_flash_close();
	
	idx_cnt += ONE_PACK_SIZE;
	
    crc_code = modbus_calc_crc(&master_tx_buf[1] , idx_cnt - 1);
    master_tx_buf[idx_cnt ++] = crc_code >> 8;
    master_tx_buf[idx_cnt ++] = crc_code & 0xff;
    master_tx_buf[idx_cnt ++] = 0xCC;

    If_com_send_str(com_id ,master_tx_buf , idx_cnt);
}

static uint8_t iap_master_is_status_ok(uint16_t now_pack_sn,uint8_t *rx_buf, uint16_t rx_num)
{
    uint16_t calc_crc = 0;
    uint16_t recv_crc = 0;
	uint16_t pack_sn = 0;
    if((0xBB == rx_buf[0]) && (rx_buf[rx_num - 1] == 0xCC))
    {
        recv_crc = (rx_buf[rx_num - 3] << 8) + rx_buf[rx_num - 2];
        calc_crc = modbus_calc_crc(&rx_buf[1] , rx_num - 4);   
		pack_sn = (rx_buf[4] << 8) + rx_buf[5];
        if(recv_crc == calc_crc)
        {
            if((0 == rx_buf[3]) && (pack_sn == now_pack_sn))
                return TRUE;
            else
                return FALSE;
        }
    }

    return FALSE;
}

/** ------------------------------------------------------------------------- *
  *                              Local function
 ** ------------------------------------------------------------------------- */

/********** Copyright (c) 2023 JBD-Energy Storage Technology Co. LTD *********/
